/**
 * 
 */
package org.h2.table;

import java.math.BigDecimal;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Hashtable;

import org.h2.engine.Mode;
import org.h2.engine.Session;
import org.h2.index.Cursor;
import org.h2.message.Message;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.tools.SimpleResultSet;
import org.h2.util.ByteUtils;
import org.h2.util.MathUtils;
import org.h2.util.StringUtils;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueByte;
import org.h2.value.ValueBytes;
import org.h2.value.ValueDate;
import org.h2.value.ValueDecimal;
import org.h2.value.ValueDouble;
import org.h2.value.ValueFloat;
import org.h2.value.ValueInt;
import org.h2.value.ValueJavaObject;
import org.h2.value.ValueLob;
import org.h2.value.ValueLong;
import org.h2.value.ValueNull;
import org.h2.value.ValueResultSet;
import org.h2.value.ValueShort;
import org.h2.value.ValueString;
import org.h2.value.ValueStringIgnoreCase;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
import org.h2.value.ValueUuid;

/**
 * @author falario
 *
 */
public abstract class TableExternAdapter{
	private String type;
	protected TableExtern tableExtern=null;
	protected Hashtable params;
	
	protected static final String S_FILE = "file";
	protected static final String S_STORED_COLUMNS = "savecolumns";
    
	protected static final String S_TYPE = "type";
	
//	public static int fromSQLTypeToValueType(int sqlType){
//		
////	    UNKNOWN = -1;
////		BYTE = 2
////		SHORT = 3
////		STRING_IGNORECASE = 14
////		RESULT_SET = 18
////		JAVA_OBJECT = 19
////		UUID = 20;
//		
//		switch(sqlType){
//			case Types.ARRAY:
//				return Value.ARRAY;
//			case Types.BIGINT:
//				return Value.LONG;
//			case Types.BLOB:
//				return Value.BLOB;
//			case Types.BIT:
//			case Types.BOOLEAN:
//				return Value.BOOLEAN;
//			case Types.CLOB:
//				return Value.CLOB;
//			case Types.DATE:
//				return Value.DATE;
//			case Types.DECIMAL:
//				return Value.DECIMAL;
//			case Types.DOUBLE:
//			case Types.REAL:
//				return Value.DOUBLE;
//			case Types.FLOAT:
//				return Value.FLOAT;
//			case Types.INTEGER:
//			case Types.SMALLINT:
//			case Types.TINYINT:
//				return Value.INT;
//			case Types.JAVA_OBJECT:
//				return Value.JAVA_OBJECT;
//			case Types.VARCHAR:
//			case Types.LONGVARCHAR:
//			case Types.CHAR:
//				return Value.STRING;
//			case Types.NULL:
//				return Value.NULL;
//			case Types.TIME:
//				return Value.TIME;
//			case Types.TIMESTAMP:
//				return Value.TIMESTAMP;
//			case Types.VARBINARY:
//			case Types.STRUCT:
//			case Types.REF:
//			case Types.OTHER:
//			case Types.NUMERIC:
//			case Types.LONGVARBINARY:
//			case Types.DISTINCT:
//			case Types.DATALINK:
//			case Types.BINARY:
//			default:
//				return Value.UNKNOWN;
//		}
//	}
	
    public static Value getValue(int type, Object value) throws SQLException{
        // decimal conversion
    	if(value==null){
    		return ValueNull.INSTANCE;
    	}
        switch (type) {
	        case Value.BOOLEAN: {
	        	if(value instanceof Boolean){
	        		return ValueBoolean.get(((Boolean)value).booleanValue());
	        	}
	        	else if(value instanceof Byte){
	        		return ValueBoolean.get(((Byte)value).byteValue() != 0);
	        	}
	        	else if(value instanceof Short){
	        		return ValueBoolean.get(((Short)value).shortValue() != 0);
	        	}
	        	else if(value instanceof Integer){
	        		return ValueBoolean.get(((Integer)value).intValue() != 0);
	        	}
	        	else if(value instanceof Long){
	        		return ValueBoolean.get(((Long)value).longValue() != 0);
	        	}
	        	else if(value instanceof BigDecimal){
	        		return ValueBoolean.get(((BigDecimal)value).doubleValue() != 0);
	        	}
	        	else if(value instanceof Double){
	        		return ValueBoolean.get(((Double)value).doubleValue() != 0);
	        	}
	        	else if(value instanceof Float){
	        		return ValueBoolean.get(((Float)value).floatValue() != 0);
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case BYTE:
	            case SHORT:
	            case INT:
	            case LONG:
	            case DECIMAL:
	            case DOUBLE:
	            case FLOAT:
	                return ValueBoolean.get(getSignum() != 0);
	            case TIME:
	            case DATE:
	            case TIMESTAMP:
	            case BYTES:
	            case JAVA_OBJECT:
	            case UUID:
	                throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, getString());
	            }            
	            break;*/
	        }
	        case Value.BYTE: {
	        	if(value instanceof Boolean){
	        		return ValueByte.get(((Boolean)value).booleanValue() ? (byte)1 : (byte)0);
	        	}
	        	else if(value instanceof Short){
	        		short s=((Short)value).shortValue();
	                if (s > Byte.MAX_VALUE || s < Byte.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueByte.get((byte)s);
	        	}
	        	else if(value instanceof Integer){
	        		int i=((Integer)value).intValue();
	                if (i > Byte.MAX_VALUE || i < Byte.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueByte.get((byte)i);
	        	}
	        	else if(value instanceof Long){
	        		long l=((Long)value).longValue();
	                if (l > Byte.MAX_VALUE || l < Byte.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueByte.get((byte)l);
	        	}
	        	else if(value instanceof BigDecimal){
	        		double bd=((BigDecimal)value).doubleValue();
	                if (bd > Byte.MAX_VALUE || bd < Byte.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueByte.get((byte)bd);
	        	}
	        	else if(value instanceof Double){
	        		double d=((Double)value).doubleValue();
	                if (d > Byte.MAX_VALUE || d < Byte.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueByte.get((byte)d);
	        	}
	        	else if(value instanceof Float){
	        		float f=((Float)value).floatValue();
	                if (f > Byte.MAX_VALUE || f < Byte.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueByte.get((byte)f);
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case BOOLEAN:
	                return ValueByte.get(getBoolean().booleanValue() ? (byte)1 : (byte)0);
	            case SHORT:
	                return ValueByte.get(convertToByte(getShort()));
	            case INT:
	                return ValueByte.get(convertToByte(getInt()));
	            case LONG:
	                return ValueByte.get(convertToByte(getLong()));
	            case DECIMAL:
	                return ValueByte.get(convertToByte(convertToLong(getBigDecimal())));
	            case DOUBLE:
	                return ValueByte.get(convertToByte(convertToLong(getDouble())));
	            case FLOAT:
	                return ValueByte.get(convertToByte(convertToLong(getFloat())));
	            }
	            break;*/
	        }
	        case Value.SHORT: {
	        	if(value instanceof Boolean){
	        		return ValueShort.get(((Boolean)value).booleanValue() ? (short)1 : (short)0);
	        	}
	        	else if(value instanceof Byte){
	        		return ValueShort.get(((Boolean)value).booleanValue() ? (short)1 : (short)0);
	        	}
	        	else if(value instanceof Integer){
	        		int i=((Integer)value).intValue();
	                if (i > Short.MAX_VALUE || i < Short.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueShort.get((short)i);
	        	}
	        	else if(value instanceof Long){
	        		long l=((Long)value).longValue();
	                if (l > Short.MAX_VALUE || l < Short.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueShort.get((short)l);
	        	}
	        	else if(value instanceof BigDecimal){
	        		double bd=((BigDecimal)value).doubleValue();
	                if (bd > Short.MAX_VALUE || bd < Short.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueShort.get((short)bd);
	        	}
	        	else if(value instanceof Double){
	        		double d=((Double)value).doubleValue();
	                if (d > Short.MAX_VALUE || d < Short.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueShort.get((short)d);
	        	}
	        	else if(value instanceof Float){
	        		float f=((Float)value).floatValue();
	                if (f > Short.MAX_VALUE || f < Short.MIN_VALUE) {
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                return ValueShort.get((short)f);
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case BOOLEAN:
	                return ValueShort.get(getBoolean().booleanValue() ? (short)1 : (short)0);
	            case BYTE:
	                return ValueShort.get(getByte());
	            case INT:
	                return ValueShort.get(convertToShort(getInt()));
	            case LONG:
	                return ValueShort.get(convertToShort(getLong()));
	            case DECIMAL:
	                return ValueShort.get(convertToShort(convertToLong(getBigDecimal())));
	            case DOUBLE:
	                return ValueShort.get(convertToShort(convertToLong(getDouble())));
	            case FLOAT:
	                return ValueShort.get(convertToShort(convertToLong(getFloat())));
	            }
	            break;*/
	        }
	        case Value.INT: {
	        	if(value instanceof Integer){
	        		return ValueInt.get(((Integer)value).intValue());
	        	}
	        	else if(value instanceof Boolean){
	        		return ValueInt.get(((Boolean)value).booleanValue() ? 1 : 0);
	        	}
	        	else if(value instanceof Byte){
	        		return ValueInt.get(((Byte)value).intValue());
	        	}
	        	else if(value instanceof Short){
	        		return ValueInt.get(((Short)value).intValue());
	        	}
	        	else if(value instanceof Long){
	        		return ValueInt.get(((Long)value).intValue());
	        	}
	        	else if(value instanceof BigDecimal){
	        		double bd=((BigDecimal)value).doubleValue();
	                if (bd > Long.MAX_VALUE || bd < Long.MIN_VALUE) {
	                    // TODO document that +Infinity, -Infinity throw an exception and NaN returns 0
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                if(Mode.getCurrentMode().roundWhenConvertToLong) {
	                    return ValueInt.get((int)Math.round(bd));
	                } else {
	                    return ValueInt.get((int)bd);
	                }
	        	}
	        	else if(value instanceof Double){
	        		double d=((Double)value).doubleValue();
	                if (d > Long.MAX_VALUE || d < Long.MIN_VALUE) {
	                    // TODO document that +Infinity, -Infinity throw an exception and NaN returns 0
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                if(Mode.getCurrentMode().roundWhenConvertToLong) {
	                    return ValueInt.get((int)Math.round(d));
	                } else {
	                    return ValueInt.get((int)d);
	                }
	        	}
	        	else if(value instanceof Float){
	        		float f=((Float)value).floatValue();
	                if (f > Long.MAX_VALUE || f < Long.MIN_VALUE) {
	                    // TODO document that +Infinity, -Infinity throw an exception and NaN returns 0
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                if(Mode.getCurrentMode().roundWhenConvertToLong) {
	                    return ValueInt.get(Math.round(f));
	                } else {
	                    return ValueInt.get((int)f);
	                }
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case BOOLEAN:
	                return ValueInt.get(getBoolean().booleanValue() ? 1 : 0);
	            case BYTE:
	                return ValueInt.get(getByte());
	            case SHORT:
	                return ValueInt.get(getShort());
	            case LONG:
	                return ValueInt.get(convertToInt(getLong()));
	            case DECIMAL:
	                return ValueInt.get(convertToInt(convertToLong(getBigDecimal())));
	            case DOUBLE:
	                return ValueInt.get(convertToInt(convertToLong(getDouble())));
	            case FLOAT:
	                return ValueInt.get(convertToInt(convertToLong(getFloat())));
	            }
	            break;*/
	        }
	        case Value.LONG: {
	        	if(value instanceof Boolean){
	        		return ValueLong.get(((Boolean)value).booleanValue() ? 1 : 0);
	        	}
	        	else if(value instanceof Byte){
	        		return ValueLong.get(((Byte)value).longValue());
	        	}
	        	else if(value instanceof Short){
	        		return ValueLong.get(((Byte)value).longValue());
	        	}
	        	else if(value instanceof Integer){
	        		return ValueLong.get(((Integer)value).longValue());
	        	}
	        	else if(value instanceof BigDecimal){
	        		double bd=((BigDecimal)value).doubleValue();
	                if (bd > Long.MAX_VALUE || bd < Long.MIN_VALUE) {
	                    // TODO document that +Infinity, -Infinity throw an exception and NaN returns 0
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                if(Mode.getCurrentMode().roundWhenConvertToLong) {
	                    return ValueLong.get((long)Math.round(bd));
	                } else {
	                    return ValueLong.get((long)bd);
	                }
	        	}
	        	else if(value instanceof Double){
	        		double d=((Double)value).doubleValue();
	                if (d > Long.MAX_VALUE || d < Long.MIN_VALUE) {
	                    // TODO document that +Infinity, -Infinity throw an exception and NaN returns 0
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                if(Mode.getCurrentMode().roundWhenConvertToLong) {
	                    return ValueLong.get((long)Math.round(d));
	                } else {
	                    return ValueLong.get((long)d);
	                }
	        	}
	        	else if(value instanceof Float){
	        		float f=((Float)value).floatValue();
	                if (f > Long.MAX_VALUE || f < Long.MIN_VALUE) {
	                    // TODO document that +Infinity, -Infinity throw an exception and NaN returns 0
	                    throw Message.getSQLException(Message.NUMERIC_VALUE_OUT_OF_RANGE);
	                }
	                if(Mode.getCurrentMode().roundWhenConvertToLong) {
	                    return ValueFloat.get((long)Math.round(f));
	                } else {
	                    return ValueFloat.get((long)f);
	                }
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case BOOLEAN:
	                return ValueLong.get(getBoolean().booleanValue() ? 1 : 0);
	            case BYTE:
	                return ValueLong.get(getByte());
	            case SHORT:
	                return ValueLong.get(getShort());
	            case INT:
	                return ValueLong.get(getInt());
	            case DECIMAL:
	                return ValueLong.get(convertToLong(getBigDecimal()));
	            case DOUBLE:
	                return ValueLong.get(convertToLong(getDouble()));
	            case FLOAT:
	                return ValueLong.get(convertToLong(getFloat()));
	            }
	            break;*/
	        }
	        case Value.DECIMAL: {
	        	if(value instanceof Boolean){
	        		return ValueDecimal.get(new BigDecimal(((Boolean)value).booleanValue() ? "1" : "0"));
	        	}
	        	else if(value instanceof Byte){
	        		return ValueDecimal.get(new BigDecimal("" + ((Byte)value).byteValue()));
	        	}
	        	else if(value instanceof Short){
	        		return ValueDecimal.get((new BigDecimal("" + ((Short)value).shortValue())));
	        	}
	        	else if(value instanceof Integer){
	        		return ValueDecimal.get((new BigDecimal("" + ((Integer)value).intValue())));
	        	}
	        	else if(value instanceof Long){
	        		return ValueDecimal.get((new BigDecimal("" + ((Long)value).longValue())));
	        	}
	        	else if(value instanceof Double){
	                double d = ((Double)value).doubleValue();
	                if(Double.isInfinite(d) || Double.isNaN(d)) {
	                    throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, ""+d);
	                }
	                return ValueDecimal.get(new BigDecimal(d));
	        	}
	        	else if(value instanceof Float){
	        		float f=((Float)value).floatValue();
	                if(Float.isInfinite(f) || Float.isNaN(f)) {
	                    throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, ""+f);
	                }
	                return ValueDecimal.get(new BigDecimal(f));
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            // convert to string is required for JDK 1.4
	            /*switch (getType()) {
	            case BOOLEAN:
	                return ValueDecimal.get(new BigDecimal(getBoolean().booleanValue() ? "1" : "0"));
	            case BYTE:
	                return ValueDecimal.get(new BigDecimal("" + getByte()));
	            case SHORT:
	                return ValueDecimal.get(new BigDecimal("" + getShort()));
	            case INT:
	                return ValueDecimal.get(new BigDecimal("" + getInt()));
	            case LONG:
	                return ValueDecimal.get(new BigDecimal("" + getLong()));
	            case DOUBLE: {
	                double d = getDouble();
	                if(Double.isInfinite(d) || Double.isNaN(d)) {
	                    throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, ""+d);
	                }
	                return ValueDecimal.get(new BigDecimal(d));
	            }
	            case FLOAT: {
	                float f = getFloat();
	                if(Float.isInfinite(f) || Float.isNaN(f)) {
	                    throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, ""+f);
	                }
	                return ValueDecimal.get(new BigDecimal(f));
	            }
	            }
	            break;*/
	        }
	        case Value.DOUBLE: {
	        	if(value instanceof Double){
	        		return ValueDouble.get(((Double)value).doubleValue());
	        	}
	        	else if(value instanceof Boolean){
	        		return ValueDouble.get(((Boolean)value).booleanValue() ? 1 : 0);
	        	}
	        	else if(value instanceof Byte){
	        		return ValueDouble.get(((Byte)value).byteValue());
	        	}
	        	else if(value instanceof Short){
	        		return ValueDouble.get(((Short)value).shortValue());
	        	}
	        	else if(value instanceof Integer){
	        		return ValueDouble.get(((Integer)value).intValue());
	        	}
	        	else if(value instanceof Long){
	        		return ValueDouble.get(((Long)value).longValue());
	        	}
	        	else if(value instanceof BigDecimal){
	        		return ValueDouble.get(((BigDecimal)value).doubleValue());
	        	}
	        	else if(value instanceof Float){
	        		return ValueDouble.get(((Float)value).floatValue());
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case BOOLEAN:
	                return ValueDouble.get(getBoolean().booleanValue() ? 1 : 0);
	            case BYTE:
	                return ValueDouble.get(getByte());
	            case SHORT:
	                return ValueDouble.get(getShort());
	            case INT:
	                return ValueDouble.get(getInt());
	            case LONG:
	                return ValueDouble.get(getLong());
	            case DECIMAL:
	                return ValueDouble.get(getBigDecimal().doubleValue());
	            case FLOAT:
	                return ValueDouble.get(getFloat());
	            }
	            break;*/
	        }
	        case Value.FLOAT: {
	        	if(value instanceof Boolean){
	        		return ValueFloat.get(((Boolean)value).booleanValue() ? 1 : 0);
	        	}
	        	else if(value instanceof Byte){
	        		return ValueFloat.get(((Byte)value).byteValue());
	        	}
	        	else if(value instanceof Short){
	        		return ValueFloat.get(((Short)value).shortValue());
	        	}
	        	else if(value instanceof Integer){
	        		return ValueFloat.get(((Integer)value).intValue());
	        	}
	        	else if(value instanceof Long){
	        		return ValueFloat.get(((Long)value).longValue());
	        	}
	        	else if(value instanceof BigDecimal){
	        		return ValueFloat.get(((BigDecimal)value).floatValue());
	        	}
	        	else if(value instanceof Double){
	        		return ValueFloat.get(((Double)value).floatValue());
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case BOOLEAN:
	                return ValueFloat.get(getBoolean().booleanValue() ? 1 : 0);
	            case BYTE:
	                return ValueFloat.get(getByte());
	            case SHORT:
	                return ValueFloat.get(getShort());
	            case INT:
	                return ValueFloat.get(getInt());
	            case LONG:
	                return ValueFloat.get(getLong());
	            case DECIMAL:
	                return ValueFloat.get(getBigDecimal().floatValue());
	            case DOUBLE:
	                return ValueFloat.get((float)getDouble());
	            }
	            break;*/
	        }
	        case Value.DATE: {
	        	if(value instanceof Time){
	        		return ValueDate.get(new Date(((Time)value).getTime()));
	        	}
	        	else if(value instanceof Timestamp){
	        		return ValueDate.get(new Date(((Timestamp)value).getTime()));
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case TIME:
	                return ValueDate.get(new Date(getTimeNoCopy().getTime()));
	            case TIMESTAMP:
	                return ValueDate.get(new Date(getTimestampNoCopy().getTime()));
	            }
	            break;*/
	        }
	        case Value.TIME: {
	        	if(value instanceof Date){
	        		return ValueTime.get(new Time(((Date)value).getTime()));
	        	}
	        	else if(value instanceof Timestamp){
	        		return ValueTime.get(new Time(((Timestamp)value).getTime()));
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case DATE:
	                // need to normalize the year, month and day
	                return ValueTime.get(new Time(getDateNoCopy().getTime()));
	            case TIMESTAMP:
	                // need to normalize the year, month and day
	                return ValueTime.get(new Time(getTimestampNoCopy().getTime()));
	            }
	            break;*/
	        }
	        case Value.TIMESTAMP: {
	        	if(value instanceof Time){
	        		return ValueTimestamp.getNoCopy(new Timestamp(((Time)value).getTime()));
	        	}
	        	else if(value instanceof Date){
	        		return ValueTimestamp.getNoCopy(new Timestamp(((Time)value).getTime()));
	        	}
	        	else{
	        		throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	}
	        	
	            /*switch (getType()) {
	            case TIME:
	                return ValueTimestamp.getNoCopy(new Timestamp(getTimeNoCopy().getTime()));
	            case DATE:
	                return ValueTimestamp.getNoCopy(new Timestamp(getDateNoCopy().getTime()));
	            }
	            break;*/
	        }
	        case Value.BYTES: {
	        	throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	
	            /*switch(getType()) {
	            case JAVA_OBJECT:
	            case BLOB:
	            case UUID:
	                return ValueBytes.getNoCopy(getBytesNoCopy());
	            }
	            break;*/
	        }
	        case Value.JAVA_OBJECT: {
	        	return ValueBytes.get((byte[])value);
	        	//throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	
	            /*switch(getType()) {
	            case BYTES:
	            case BLOB:
	                return ValueBytes.getNoCopy(getBytesNoCopy());
	            }
	            break;*/
	        }
	        case Value.BLOB: {
	        	throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	
	            /*switch(getType()) {
	            case BYTES:
	                return ValueLob.createSmallLob(Value.BLOB, getBytesNoCopy());
	            }           
	            break;*/
	        }
	        case Value.UUID: {
	        	throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, String.valueOf(value));
	        	
	            /*switch(getType()) {
	            case BYTES:
	                return ValueUuid.get(getBytesNoCopy());    
	            }*/
	        }
        }
        // conversion by parsing the string value
        String s = String.valueOf(value);
        try {
            switch (type) {
            case Value.NULL:
                return ValueNull.INSTANCE;
            case Value.BOOLEAN: {
                if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("t") || s.equalsIgnoreCase("yes") || s.equalsIgnoreCase("y")) {
                    return ValueBoolean.get(true);
                } else if (s.equalsIgnoreCase("false") || s.equalsIgnoreCase("f") || s.equalsIgnoreCase("no") || s.equalsIgnoreCase("n")) {
                    return ValueBoolean.get(false);
                } else {
                    // convert to a number, and if it is not 0 then it is true
                    return ValueBoolean.get(new BigDecimal(s).signum() != 0);
                }
            }
            case Value.BYTE:
                return ValueByte.get(MathUtils.decodeByte(s.trim()));
            case Value.SHORT:
                return ValueShort.get(MathUtils.decodeShort(s.trim()));
            case Value.INT:
                return ValueInt.get(MathUtils.decodeInt(s.trim()));
            case Value.LONG:
                return ValueLong.get(MathUtils.decodeLong(s.trim()));
            case Value.DECIMAL:
                return ValueDecimal.get(new BigDecimal(s.trim()));
            case Value.TIME:
                return ValueTime.get(ValueTime.parseTime(s.trim()));
            case Value.DATE:
                return ValueDate.get(ValueDate.parseDate(s.trim()));
            case Value.TIMESTAMP:
                return ValueTimestamp.get(ValueTimestamp.parseTimestamp(s.trim()));
            case Value.BYTES:
                return ValueBytes.getNoCopy(ByteUtils.convertStringToBytes(s.trim()));
            case Value.JAVA_OBJECT:
                return ValueJavaObject.getNoCopy(ByteUtils.convertStringToBytes(s.trim()));
            case Value.STRING:
                return ValueString.get(s);
            case Value.STRING_IGNORECASE:
                return ValueStringIgnoreCase.get(s);
            case Value.DOUBLE:
                return ValueDouble.get(Double.parseDouble(s.trim()));
            case Value.FLOAT:
                return ValueFloat.get(Float.parseFloat(s.trim()));
            case Value.CLOB:
                return ValueLob.createSmallLob(Value.CLOB, StringUtils.utf8Encode(s));
            case Value.BLOB:
                return ValueLob.createSmallLob(Value.BLOB, ByteUtils.convertStringToBytes(s.trim()));
            case Value.ARRAY:
                return ValueArray.get(new Value[]{ValueString.get(s)});
            case Value.RESULT_SET: {
                SimpleResultSet rs = new SimpleResultSet();
                rs.addColumn("X", Types.VARCHAR, s.length(), 0);
                rs.addRow(new String[]{s});
                return ValueResultSet.get(rs);
            }
            case Value.UUID:
                return ValueUuid.get(s);
            default:
                throw Message.getInternalError("type=" + type);
            }
        }
        catch(SQLException except){
        	throw except;
        }
        catch (NumberFormatException e) {
            throw Message.getSQLException(Message.DATA_CONVERSION_ERROR_1, new String[] { s }, e);
        }
    }

	/**
	 * 
	 */
	protected TableExternAdapter() {
		
	}
	
	public void initialize(TableExtern table, Hashtable parameters, Column[] columns) throws SQLException{
		this.tableExtern=table;
		this.params=parameters;
		if(columns==null){
			this.setColumns(this.getColumns());
			this.tableExtern.setColumns(this.getColumns());
		}
		else{
			this.setColumns(columns);
			this.tableExtern.setColumns(columns);
		}
	}
	
	public void initialize(TableExtern table, Hashtable parameters) throws SQLException{
		this.initialize(table, parameters, this.getColumns());
	}
	
	protected void setTypeName(String type){
		this.type=type;
	}
	
	public String getTypeName(){
		return this.type;
	}
	
	public Hashtable getParams(){
		return this.params;
	}
	
	protected TableExtern getTableExtern(){
		return this.tableExtern;
	}
	
	public abstract Column[] getColumns() throws SQLException;
	
	public abstract void setColumns(Column[] columns);
	
	public abstract void checkParameters() throws SQLException;
	
	public abstract String getParam(String key) throws SQLException;
	
	public abstract Cursor getData(Session session, SearchRow first, SearchRow last) throws SQLException;
	
	public abstract boolean closeSource();
	
	public abstract void drop();
	
	public abstract void insertData(Session session, Row row) throws SQLException;
	
	public abstract void removeData(Session session, Row row) throws SQLException;
	
	public abstract boolean canGetRowCount();
	
	public abstract int getRowCount();
	
	public abstract boolean canGetRowPos();
	
	public abstract int getRowPos();
	
	public abstract boolean needRebuild();
	
	public abstract boolean canGetFirstOrLast();
	
	public abstract Value findFirstOrLast(Session session, boolean first);
}
